home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / osrc.arc / DOMAIN.C < prev    next >
Encoding:
C/C++ Source or Header  |  1989-04-05  |  24.0 KB  |  1,082 lines

  1. #include <stdio.h>
  2. #include <ctype.h>
  3. #include "global.h"
  4. #include "mbuf.h"
  5. #include "timer.h"
  6. #include "netuser.h"
  7. #include "socket.h"
  8. #include "cmdparse.h"
  9. #include "proc.h"
  10. #include "domain.h"
  11.  
  12. void drx();
  13.  
  14. extern int errno;
  15. extern int32 Clock;
  16. extern int32 Ip_addr;
  17.  
  18. struct rr *Rrlist[NRLIST];
  19. struct dserver *Dlist;        /* List of potential servers */
  20. struct dserver *Dserver;    /* Current one being used */
  21. char *Dsuffix;            /* Default suffix for names without periods */
  22. int Dsocket;            /* Socket to use for domain queries */
  23. struct proc *Drx;        /* Task ID of domain receiver */
  24. int Ddebug = 0;
  25. char *Dtypes[] = {
  26.     "",
  27.     "A",
  28.     "NS",
  29.     "MD",
  30.     "MF",
  31.     "CNAME",
  32.     "SOA",
  33.     "MB",
  34.     "MG",
  35.     "MR",
  36.     "NULL",
  37.     "WKS",
  38.     "PTR",
  39.     "HINFO",
  40.     "MINFO",
  41.     "MX",
  42.     "TXT"
  43. };
  44. int Ndtypes = 17;
  45. static char delim[] = " \t\r\n";
  46. static struct {
  47.     char *name;
  48.     int32 address;
  49. } cache;
  50.  
  51. struct cmds Dcmds[] = {
  52.     "addserver",    doadds,        0, 0, NULLCHAR,
  53.     "dropserver",    dodropds,    0, 0, NULLCHAR,
  54.     "suffix",    dosuffix,    0, 0, NULLCHAR,
  55.     "trace",    dodtrace,    0, 0, NULLCHAR,
  56.     NULLCHAR,    NULLFP,        0, 0, "domain subcommands: addserver dropserver suffix trace",
  57. };
  58. int
  59. dodtrace(argc,argv)
  60. int argc;
  61. char *argv[];
  62. {
  63.     if(argc < 2){
  64.         printf("Domain trace: %s\n",Ddebug ? "On" : "Off");
  65.     } else {
  66.         if(strcmp(argv[1],"on") == 0)
  67.             Ddebug = 1;
  68.         else
  69.             Ddebug = 0;
  70.     }
  71.     return 0;
  72. }
  73. int
  74. dodomain(argc,argv,envp)
  75. int argc;
  76. char *argv[];
  77. void *envp;
  78. {
  79.     return subcmd(Dcmds,argc,argv,envp);    
  80. }
  81. int
  82. dosuffix(argc,argv)
  83. int argc;
  84. char *argv[];
  85. {
  86.     if(argc < 2){
  87.         if(Dsuffix != NULLCHAR)
  88.             printf("%s\n",Dsuffix);
  89.         return 0;
  90.     }
  91.     free(Dsuffix);
  92.     Dsuffix = strdup(argv[1]);
  93.     return 0;
  94. }
  95. int
  96. doadds(argc,argv)
  97. int argc;
  98. char *argv[];
  99. {
  100.     struct dserver *dp;
  101.     int32 address;
  102.  
  103.     if((address = resolve(argv[1])) == 0){
  104.         printf("Resolver %s unknown\n",argv[1]);
  105.         return 1;
  106.     }
  107.     dp = (struct dserver *)calloc(1,sizeof(struct dserver));
  108.     dp->address = address;
  109.     dp->srtt = (5L * 1000) / MSPTICK; /* About 5 sec */
  110.     dp->timeout = dp->srtt * 2;
  111.     dp->mdev = 0;
  112.     dp->next = Dlist;
  113.     if(dp->next != NULLDOM)
  114.         dp->next->prev = dp;
  115.     Dlist = dp;
  116.     Dserver = dp;    /* Make this the first one we try next */
  117.     if(Drx == NULLPROC){
  118.         /* Start domain task upon first addserver */
  119.         Drx = newproc("Domain",1024,drx,0,NULL,NULL);
  120.     }
  121.     return 0;
  122. }
  123. int
  124. dodropds(argc,argv)
  125. int argc;
  126. char *argv[];
  127. {
  128.     struct dserver *dp;
  129.     int32 addr;
  130.  
  131.     addr = resolve(argv[1]);
  132.     for(dp = Dlist;dp != NULLDOM;dp = dp->next)
  133.         if(addr == dp->address)
  134.             break;
  135.  
  136.     if(dp == NULLDOM){
  137.         printf("Not found\n");
  138.         return 1;
  139.     }
  140.     if(dp->prev != NULLDOM)
  141.         dp->prev->next = dp->next;
  142.     else
  143.         Dlist = dp->next;
  144.     if(dp->next != NULLDOM)
  145.         dp->next->prev = dp->prev;
  146.  
  147.     if(Dserver == dp)
  148.         Dserver = Dlist;
  149.     free((char *)dp);
  150.     return 0;
  151. }
  152.  
  153. /* Search local domain file for resource record of specified type.
  154.  * If a record is found, the domain file pointer is left just after it. If
  155.  * not, the file is rewound.
  156.  */
  157. static struct rr *
  158. dfind(dbase,name,type)
  159. FILE *dbase;
  160. char *name;
  161. int type;
  162. {
  163.     struct rr *rrp;
  164.     int nlen;
  165.  
  166.     /* Search file */
  167.     while((rrp = getrr(dbase)) != NULLRR){
  168.         if((nlen = strlen(name)) == strlen(rrp->name)
  169.          && strnicmp(name,rrp->name,nlen) == 0
  170.          && rrp->class == CLASS_IN
  171.          && rrp->type == type)
  172.             break;
  173.         free_rr(rrp);
  174.         pwait(NULL);    /* Give up CPU for a while, this is slow */
  175.     }
  176.     if(rrp == NULLRR)
  177.         rewind(dbase);
  178.     return rrp;
  179. }
  180. static struct rr *
  181. getrr(fp)
  182. FILE *fp;
  183. {
  184.     char *line,*strtok();
  185.     struct rr *rrp;
  186.     char *name,*ttl,*class,*type,*data;
  187.     int i;
  188.  
  189.     line = malloc(256);
  190.     /* Search file */
  191.     while(fgets(line,256,fp),!feof(fp)){
  192.         if(line[0] != '#')
  193.             break;
  194.     }
  195.     if(feof(fp) || (rrp = (struct rr *)calloc(1,sizeof(struct rr))) == NULLRR){
  196.         free(line);
  197.         return NULLRR;
  198.     }
  199.     name = strtok(line,delim);
  200.     ttl = strtok(NULLCHAR,delim);
  201.     class = strtok(NULLCHAR,delim);
  202.     type = strtok(NULLCHAR,delim);
  203.     data = strtok(NULLCHAR,delim);
  204.     
  205.     rrp->name = strdup(name);
  206.     if(!isdigit(ttl[0])){
  207.         /* Optional ttl field is missing; slide the other fields over */
  208.         data = type;
  209.         type = class;
  210.         class = ttl;
  211.         ttl = NULLCHAR;
  212.     } else {
  213.         rrp->ttl = atol(ttl);
  214.     }
  215.     for(i=0;i<NRLIST;i++){
  216.         if(strcmp(type,Dtypes[i]) == 0){
  217.             rrp->type = i;
  218.             break;
  219.         }
  220.     }
  221.     if(strcmp(class,"IN") == 0)
  222.         rrp->class = CLASS_IN;
  223.  
  224.     if(data == NULLCHAR){
  225.         /* Empty record, just return */
  226.         free(line);
  227.         return rrp;
  228.     }
  229.     switch(rrp->type){
  230.     case TYPE_CNAME:
  231.     case TYPE_MB:
  232.     case TYPE_MG:
  233.     case TYPE_MR:
  234.     case TYPE_NS:
  235.     case TYPE_PTR:
  236.     case TYPE_TXT:
  237.         rrp->rdlength = strlen(data);
  238.         rrp->rdata.name = strdup(data);
  239.         break;
  240.     case TYPE_A:
  241.         rrp->rdlength = 4;
  242.         rrp->rdata.addr = aton(data);
  243.         break;
  244.     case TYPE_HINFO:
  245.         rrp->rdlength = strlen(data);
  246.         rrp->rdata.hinfo.cpu = strdup(data);
  247.         if((data = strtok(NULLCHAR,delim)) != NULLCHAR){
  248.             rrp->rdlength += strlen(data);
  249.             rrp->rdata.hinfo.os = strdup(data);
  250.         }
  251.         break;
  252.     case TYPE_MX:
  253.         rrp->rdata.mx.pref = atoi(data);
  254.         rrp->rdlength = 2;
  255.  
  256.         /* Get domain name of exchanger */
  257.         if((data = strtok(NULLCHAR,delim)) != NULLCHAR){
  258.             rrp->rdlength += strlen(data);
  259.             rrp->rdata.mx.exch = strdup(data);
  260.         }
  261.         break;
  262.     case TYPE_SOA:
  263.         /* Get domain name of master name server */
  264.         rrp->rdlength = strlen(data);
  265.         rrp->rdata.soa.mname = strdup(data);
  266.  
  267.         /* Get domain name of irresponsible person */
  268.         if((data = strtok(NULLCHAR,delim)) != NULLCHAR){
  269.             rrp->rdata.soa.rname = strdup(data);
  270.             rrp->rdlength += strlen(data);
  271.         }
  272.         data = strtok(NULLCHAR,delim);
  273.         rrp->rdata.soa.serial = atol(data);
  274.         data = strtok(NULLCHAR,delim);
  275.         rrp->rdata.soa.refresh = atol(data);
  276.         data = strtok(NULLCHAR,delim);
  277.         rrp->rdata.soa.retry = atol(data);
  278.         data = strtok(NULLCHAR,delim);
  279.         rrp->rdata.soa.expire = atol(data);
  280.         data = strtok(NULLCHAR,delim);
  281.         rrp->rdata.soa.minimum = atol(data);
  282.         rrp->rdlength += 20;
  283.         break;
  284.     }
  285.     free(line);
  286.     return rrp;
  287. }
  288. /* Search for address record in local database, looking first for PTR
  289.  * and CNAME records. Return values:
  290.  *  0xffffffff    Not found (domain name may exist, but we don't know yet)
  291.  *  0        Domain name definitely doesn't exist (we have a null record)
  292.  */
  293. int32
  294. dresolve(name)
  295. char *name;
  296. {
  297.     register struct rr *rrp;
  298.     char *pname = NULLCHAR;
  299.     char *cname = NULLCHAR;
  300.     int32 result;
  301.     FILE *dbase;
  302.  
  303.     if(cache.name != NULLCHAR && strcmp(cache.name,name) == 0)
  304.         return cache.address;
  305.  
  306.     if((dbase = fopen(Dfile,READ_TEXT)) == NULLFILE)
  307.         return 0xffffffff;
  308.  
  309.     /* This code can handle a few weird cases. It works when there's
  310.      * a PTR to a CNAME to an A record, as well as when there's a
  311.      * a CNAME to a PTR to an A. But it allows only one of each kind
  312.      * of indirection to prevent infinite loops.
  313.      */
  314.     while((rrp = dfind(dbase,name,TYPE_A)) == NULLRR){
  315.         /* An address record didn't exist, let's see if it's an alias */
  316.         if(cname == NULLCHAR && (rrp = dfind(dbase,name,TYPE_CNAME)) != NULLRR){
  317.             if((cname = strdup(rrp->rdata.name)) == NULLCHAR)
  318.                 break;
  319.             name = cname;
  320.             rewind(dbase);
  321.             free_rr(rrp);
  322.             continue;    /* Try again */
  323.         }
  324.         /* Lacking that, try a pointer entry... */
  325.         if(pname == NULLCHAR && (rrp = dfind(dbase,name,TYPE_PTR)) != NULLRR){
  326.             if((pname = strdup(rrp->rdata.name)) == NULLCHAR)
  327.                 break;
  328.             name = pname;
  329.             rewind(dbase);
  330.             free_rr(rrp);
  331.             continue;
  332.         }
  333.         /* Nope, nothing. Give up */
  334.         break;
  335.     }
  336.     fclose(dbase);
  337.     free(pname);
  338.     free(cname);    
  339.  
  340.     if(rrp == NULLRR){
  341.         result = 0xffffffff;        /* No record in database */
  342.     } else {
  343.         if(rrp->rdlength == 0)
  344.             result = 0;        /* Negative response record */
  345.         else
  346.             result = rrp->rdata.addr;    /* Normal return */
  347.         free(cache.name);
  348.         cache.name = strdup(name);
  349.         cache.address = result;
  350.         free_rr(rrp);
  351.     }
  352.     return result;
  353. }
  354.  
  355. /* Main entry point for domain name -> address resolution. Returns 0 if
  356.  * name is definitely not valid.
  357.  */
  358. int32
  359. resolve(name)
  360. char *name;
  361. {
  362.     char *buf;
  363.     int32 addr;
  364.     struct dserver *dp;
  365.     int len;
  366.     struct sockaddr_in server;
  367.     char *tname = NULLCHAR;
  368.     char *pname = NULLCHAR;
  369.  
  370.     if(name == NULLCHAR)
  371.         return 0;
  372.  
  373.     if(*name == '[')
  374.         return aton(name + 1);
  375.  
  376.     if(strchr(name,'.') == NULLCHAR && Dsuffix != NULLCHAR){
  377.         /* Append default suffix */
  378.         tname = malloc(strlen(name)+strlen(Dsuffix)+2);
  379.         sprintf(tname,"%s.%s",name,Dsuffix);
  380.         name = tname;
  381.     }
  382.     if(name[strlen(name)-1] != '.'){
  383.         /* Append trailing dot */
  384.         pname = malloc(strlen(name)+2);
  385.         sprintf(pname,"%s.",name);
  386.         name = pname;
  387.     }
  388.     dp = Dserver;
  389.     while((addr = dresolve(name)) == 0xffffffff){
  390.         if(dp == NULLDOM){
  391.             addr = 0;    /* Unknown, and no servers */
  392.             break;
  393.         }
  394.         /* Not in file, send query */
  395.         buf = malloc(512);
  396.         len = res_mkquery(0,name,CLASS_IN,TYPE_A,NULLCHAR,0,0,buf,512);
  397.         server.sin_family = AF_INET;
  398.         server.sin_port = IPPORT_DOMAIN;
  399.         server.sin_addr.s_addr = dp->address;
  400.         sendto(Dsocket,buf,len,0,(char *)&server,sizeof(server));
  401.         free(buf);
  402.         alarm(dp->timeout);
  403.         /* Wait for something to happen */
  404.         len = pwait(&Dsocket);
  405.         alarm(0L);
  406.         switch(len){
  407.         case -1:
  408.             addr = 0;
  409.             goto quit;
  410.         case 0:
  411.             break;
  412.         case 1:
  413.             /* Timeout; back off this one and try another server */
  414.             dp->timeout <<= 1;
  415.             if((dp = dp->next) == NULLDOM)
  416.                 dp = Dlist;
  417.             break;
  418.         }
  419.     }
  420. quit:    free(tname);
  421.     free(pname);
  422.     return addr;
  423. }
  424. static int
  425. res_mkquery(op,dname,class,type,data,datalen,newrr,buffer,buflen)
  426. int16 op;    /* operation */
  427. char *dname;    /* Domain name */
  428. int16 class;    /* Class of inquiry (IN, etc) */
  429. int16 type;    /* Type of inquiry (A, MX, etc) */
  430. char *data;
  431. int16 datalen;
  432. int16 newrr;
  433. char *buffer;    /* Area for query */
  434. int16 buflen;    /* Length of same */
  435. {
  436.     char *cp,*cp1;
  437.     int16 parameter;
  438.     int16 dlen,len;
  439.  
  440.     cp = buffer;
  441.     cp = put16(cp,(int16)Clock);    /* Use clock for timestamping */
  442.     parameter = 0x100;    /* Recursion desired */
  443.     cp = put16(cp,parameter);
  444.     cp = put16(cp,1);
  445.     cp = put16(cp,0);
  446.     cp = put16(cp,0);
  447.     cp = put16(cp,0);
  448.     dlen = strlen(dname);
  449.     for(;;){
  450.         /* Look for next dot */
  451.         cp1 = strchr(dname,'.');
  452.         if(cp1 != NULLCHAR)
  453.             len = cp1-dname;    /* More to come */
  454.         else
  455.             len = dlen;    /* Last component */
  456.         *cp++ = len;        /* Write length of component */
  457.         if(len == 0)
  458.             break;
  459.         /* Copy component up to (but not including) dot */
  460.         strncpy(cp,dname,len);
  461.         cp += len;
  462.         if(cp1 == NULLCHAR){
  463.             *cp++ = 0;    /* Last one; write null and finish */
  464.             break;
  465.         }
  466.         dname += len+1;
  467.         dlen -= len+1;
  468.     }
  469.     cp = put16(cp,type);
  470.     cp = put16(cp,class);
  471.     return cp - buffer;
  472. }
  473. /* Convert a compressed domain name to the human-readable form */
  474. static int
  475. dn_expand(msg,eom,compressed,full,fullen)
  476. char *msg;        /* Complete domain message */
  477. char *eom;
  478. char *compressed;    /* Pointer to compressed name */
  479. char *full;        /* Pointer to result buffer */
  480. int fullen;        /* Length of same */
  481. {
  482.     unsigned int slen;    /* Length of current segment */
  483.     register char *cp;
  484.     unsigned int clen = 0;    /* Total length of compressed name */
  485.     int indirect = 0;    /* Set if indirection encountered */
  486.     int nseg = 0;        /* Total number of segments in name */
  487.  
  488.     cp = compressed;
  489.     for(;;){
  490.         slen = uchar(*cp++);    /* Length of this segment */
  491.         if(!indirect)
  492.             clen++;
  493.         if((slen & 0xc0) == 0xc0){
  494.             if(!indirect)
  495.                 clen++;
  496.             indirect = 1;
  497.             /* Follow indirection */
  498.             cp = &msg[((slen & 0x3f)<<8) + uchar(*cp)];
  499.             slen = uchar(*cp++);
  500.         }
  501.         if(slen == 0)    /* zero length == all done */
  502.             break;
  503.         fullen -= slen + 1;
  504.         if(fullen < 0)
  505.             return -1;
  506.         if(!indirect)
  507.             clen += slen;
  508.         while(slen-- != 0)
  509.             *full++ = *cp++;
  510.         *full++ = '.';
  511.         nseg++;
  512.     }
  513.     if(nseg == 0){
  514.         /* Root name; represent as single dot */
  515.         *full++ = '.';
  516.         fullen--;
  517.     }
  518.     *full++ = '\0';
  519.     fullen--;
  520.     return clen;    /* Length of compressed message */
  521. }
  522. /* Process to receive all domain server replies */
  523. void
  524. drx()
  525. {
  526.     struct sockaddr_in sock,from;
  527.     int fromlen;
  528.     struct mbuf *bp;
  529.     struct dserver *dp,*dslookup();
  530.     int foo;
  531.  
  532.     Dsocket = socket(AF_INET,SOCK_DGRAM,0);
  533.     sock.sin_family = AF_INET;
  534.     sock.sin_addr.s_addr = Ip_addr;
  535.     sock.sin_port = IPPORT_DOMAIN;
  536.     if(bind(Dsocket,(char *)&sock,sizeof(sock)) == -1){
  537.         printf("Domain: can't bind (is ip address set?)\n");
  538.         Drx = NULLPROC;
  539.         return;
  540.     }
  541.     for(;;){
  542.         fromlen = sizeof(from);
  543.         foo = recv_mbuf(Dsocket,&bp,0,0,(char *)&from,&fromlen);
  544.         if(Ddebug)
  545.             printf("domain: %u bytes from %s\n",foo,
  546.              psocket((struct sockaddr *)&from));
  547.         if((dp = dslookup(from.sin_addr.s_addr)) == NULLDOM){
  548.             /* Unknown server */
  549.             if(Ddebug)
  550.                 printf("Unknown domain server!\n");
  551.             continue;
  552.         }
  553.         Dserver = dp;    /* We know this one is good */
  554.         proc_answer(dp,bp);
  555.     }
  556. }
  557. static void
  558. proc_answer(dp,bp)
  559. struct dserver *dp;
  560. struct mbuf *bp;
  561. {
  562.     FILE *fp;
  563.     struct dhdr dhdr;
  564.     int i;
  565.     int16 rtt;
  566.     long ttl = 500;    /* Default TTL for negative records without SOA */
  567.     struct rr *rrp;
  568.     struct quest *qp;
  569.  
  570.     ntohdomain(&dhdr,&bp);
  571.  
  572.     /* Compute and update the round trip time */
  573.     rtt = (int16)Clock - dhdr.id;
  574.     dp->srtt = (7 * dp->srtt + rtt) >> 3;
  575.     dp->timeout = 2*dp->srtt;
  576.  
  577.     if(Ddebug){
  578.         printf("response id %u (rtt %lu sec) qr %u opcode %u aa %u tc %u rd %u ra %u rcode %u\n",
  579.          dhdr.id,((long)rtt * MSPTICK)/1000,
  580.          dhdr.qr,dhdr.opcode,dhdr.aa,dhdr.tc,dhdr.rd,
  581.          dhdr.ra,dhdr.rcode);
  582.         printf("%u questions:\n",dhdr.qdcount);
  583.         for(i=0;i< dhdr.qdcount;i++){
  584.             qp = dhdr.qlist[i];
  585.             printf("%s type %u class %u\n",qp->qname,
  586.              qp->qtype,qp->qclass);
  587.         }
  588.     }
  589.     if(dhdr.qr == QUERY){
  590.         /* A server will eventually go here. */
  591.         free_dhdr(&dhdr);
  592.         return;
  593.     }
  594.     fp = fopen(Dfile,APPEND_TEXT);
  595.     if(fp == NULLFILE){
  596.         printf("Can't append to %s!!\n",Dfile);
  597.         free_dhdr(&dhdr);
  598.         return;
  599.     }
  600.     if(Ddebug)
  601.         printf("%u answers:\n",dhdr.ancount);
  602.     for(i=0;i< dhdr.ancount;i++){
  603.         rrp = dhdr.ans[i];
  604.         if(Ddebug)
  605.             putrr(stdout,rrp);
  606.         if(rrp->type == TYPE_SOA)
  607.             ttl = rrp->ttl;
  608.         addit(fp,rrp);
  609.     }
  610.     if(Ddebug)
  611.         printf("%u authority:\n",dhdr.nscount);
  612.     for(i=0;i< dhdr.nscount;i++){
  613.         rrp = dhdr.ns[i];
  614.         if(Ddebug){
  615.             putrr(stdout,rrp);
  616.             fflush(stdout);
  617.         }
  618.         if(rrp->type == TYPE_SOA)
  619.             ttl = rrp->ttl;
  620.         addit(fp,rrp);
  621.     }
  622.     if(Ddebug)
  623.         printf("%u additional:\n",dhdr.arcount);
  624.     for(i=0;i< dhdr.arcount;i++){
  625.         rrp = dhdr.add[i];
  626.         if(Ddebug){
  627.             putrr(stdout,rrp);
  628.             fflush(stdout);
  629.         }
  630.         if(rrp->type == TYPE_SOA)
  631.             ttl = rrp->ttl;
  632.         addit(fp,rrp);
  633.     }
  634.     if(dhdr.aa && (dhdr.rcode == NAME_ERROR || dhdr.ancount == 0)){
  635.         /* Add negative reply to file. This assumes that there was
  636.          * only one question, which is true for all questions we send.
  637.          */
  638.         qp = dhdr.qlist[0];
  639.         rrp = (struct rr *)calloc(1,sizeof(struct rr));
  640.         rrp->name = strdup(qp->qname);
  641.         rrp->type = qp->qtype;
  642.         rrp->class = qp->qclass;
  643.         rrp->ttl = ttl;
  644.         rrp->rdlength = 0;    /* no data */
  645.         addit(fp,rrp);
  646.         free_rr(rrp);
  647.     }
  648.     fclose(fp);
  649.     free_dhdr(&dhdr);
  650.     psignal(&Dsocket,0);    /* Alert anyone waiting for results */
  651. }
  652. static int
  653. ntohdomain(dhdr,bpp)
  654. struct dhdr *dhdr;
  655. struct mbuf **bpp;
  656. {
  657.     int16 tmp,len,i;
  658.     char *msg,*cp;
  659.  
  660.     len = len_mbuf(*bpp);
  661.     msg = malloc(len);
  662.     pullup(bpp,msg,len);
  663.     memset((char *)dhdr,0,sizeof(*dhdr));
  664.  
  665.         dhdr->id = get16(&msg[0]);
  666.     tmp = get16(&msg[2]);
  667.     if(tmp & 0x8000)
  668.         dhdr->qr = 1;
  669.     dhdr->opcode = (tmp >> 11) & 0xf;
  670.     if(tmp & 0x0400)
  671.         dhdr->aa = 1;
  672.     if(tmp & 0x0200)
  673.         dhdr->tc = 1;
  674.     if(tmp & 0x0100)
  675.         dhdr->rd = 1;
  676.     if(tmp & 0x0080)
  677.         dhdr->ra = 1;
  678.     dhdr->rcode = tmp & 0xf;
  679.     dhdr->qdcount = get16(&msg[4]);
  680.     dhdr->ancount = get16(&msg[6]);
  681.     dhdr->nscount = get16(&msg[8]);
  682.     dhdr->arcount = get16(&msg[10]);
  683.  
  684.     /* Now parse the variable length sections */
  685.     cp = &msg[12];
  686.  
  687.     /* Question section */
  688.     if(dhdr->qdcount != 0)
  689.         dhdr->qlist = (struct quest **)malloc(dhdr->qdcount *
  690.          sizeof(struct quest *));
  691.     for(i=0;i<dhdr->qdcount;i++){
  692.         dhdr->qlist[i] = (struct quest *)malloc(sizeof(struct quest));
  693.         if((cp = getq(dhdr->qlist[i],msg,cp)) == NULLCHAR){
  694.             free(msg);
  695.             return -1;
  696.         }
  697.     }
  698.     /* Answer section */
  699.     if(dhdr->ancount != 0)
  700.         dhdr->ans = (struct rr **)malloc(dhdr->ancount *
  701.          sizeof(struct rr *));
  702.     for(i=0;i<dhdr->ancount;i++){
  703.         dhdr->ans[i] = (struct rr *)malloc(sizeof(struct rr));
  704.         if((cp = ntohrr(dhdr->ans[i],msg,cp)) == NULLCHAR){
  705.             free(msg);
  706.             return -1;
  707.         }
  708.     }        
  709.     /* Name server (authority) section */
  710.     if(dhdr->nscount != 0)
  711.         dhdr->ns = (struct rr **)malloc(dhdr->nscount *
  712.          sizeof(struct rr *));
  713.     for(i=0;i<dhdr->nscount;i++){
  714.         dhdr->ns[i] = (struct rr *)malloc(sizeof(struct rr));
  715.         if((cp = ntohrr(dhdr->ns[i],msg,cp)) == NULLCHAR){
  716.             free(msg);
  717.             return -1;
  718.         }
  719.     }
  720.     /* Additional section */
  721.     if(dhdr->arcount != 0)
  722.         dhdr->add = (struct rr **)malloc(dhdr->arcount *
  723.          sizeof(struct rr *));
  724.     for(i=0;i<dhdr->arcount;i++){
  725.         dhdr->add[i] = (struct rr *)malloc(sizeof(struct rr));
  726.         if((cp = ntohrr(dhdr->add[i],msg,cp)) == NULLCHAR){
  727.             free(msg);
  728.             return -1;
  729.         }
  730.     }
  731.     free(msg);
  732. }
  733. static char *
  734. getq(qp,msg,cp)
  735. struct quest *qp;
  736. char *msg;
  737. char *cp;
  738. {
  739.     int len;
  740.     char *name;
  741.  
  742.     name = malloc(512);
  743.     len = dn_expand(msg,NULLCHAR,cp,name,512);
  744.     if(len == -1){
  745.         free(name);
  746.         return NULLCHAR;
  747.     }
  748.     cp += len;
  749.     qp->qname = strdup(name);
  750.     qp->qtype = get16(cp);
  751.     cp += 2;
  752.     qp->qclass = get16(cp);
  753.     cp += 2;
  754.     free(name);
  755.     return cp;
  756. }
  757. /* Read a resource record from a domain message into a host structure */
  758. static char *
  759. ntohrr(rrp,msg,cp)
  760. struct rr *rrp;    /* Pointer to allocated resource record structure */
  761. char *msg;    /* Pointer to beginning of domain message */
  762. char *cp;    /* Pointer to start of encoded RR record */
  763. {
  764.     int len;
  765.     char *name;
  766.  
  767.     if((name = malloc(512)) == NULLCHAR)
  768.         return NULLCHAR;
  769.     if((len = dn_expand(msg,NULLCHAR,cp,name,512)) == -1){
  770.         free(name);
  771.         return NULLCHAR;
  772.     }
  773.     cp += len;
  774.     rrp->name = strdup(name);
  775.     rrp->type = get16(cp);
  776.     cp += 2;
  777.     rrp->class = get16(cp);
  778.     cp+= 2;
  779.     rrp->ttl = get32(cp);
  780.     cp += 4;
  781.     rrp->rdlength = get16(cp);
  782.     cp += 2;
  783.     switch(rrp->type){
  784.     case TYPE_CNAME:
  785.     case TYPE_MB:
  786.     case TYPE_MG:
  787.     case TYPE_MR:
  788.     case TYPE_NS:
  789.     case TYPE_PTR:
  790.         /* These types all consist of a single domain name;
  791.          * convert it to ascii format
  792.          */
  793.         len = dn_expand(msg,NULLCHAR,cp,name,512);
  794.         if(len == -1){
  795.             free(name);
  796.             return NULLCHAR;
  797.         }
  798.         rrp->rdata.name = strdup(name);
  799.         cp += len;
  800.         break;
  801.     case TYPE_A:
  802.         /* Just read the address directly into the structure */
  803.         rrp->rdata.addr = get32(cp);
  804.         cp += 4;
  805.         break;
  806.     case TYPE_HINFO:
  807.         rrp->rdata.hinfo.cpu = strdup(cp);
  808.         cp += strlen(cp) + 1;
  809.  
  810.         rrp->rdata.hinfo.os = strdup(cp);
  811.         cp += strlen(cp) + 1;
  812.         break;
  813.     case TYPE_MX:
  814.         rrp->rdata.mx.pref = get16(cp);
  815.         cp += 2;
  816.         /* Get domain name of exchanger */
  817.         len = dn_expand(msg,NULLCHAR,cp,name,512);
  818.         if(len == -1){
  819.             free(name);
  820.             return NULLCHAR;
  821.         }
  822.         rrp->rdata.mx.exch = strdup(name);
  823.         cp += len;
  824.         break;
  825.     case TYPE_SOA:
  826.         /* Get domain name of name server */
  827.         len = dn_expand(msg,NULLCHAR,cp,name,512);
  828.         if(len == -1){
  829.             free(name);
  830.             return NULLCHAR;
  831.         }
  832.         rrp->rdata.soa.mname = strdup(name);
  833.         cp += len;
  834.  
  835.         /* Get domain name of responsible person */
  836.         len = dn_expand(msg,NULLCHAR,cp,name,512);
  837.         if(len == -1){
  838.             free(name);
  839.             return NULLCHAR;
  840.         }
  841.         rrp->rdata.soa.rname = strdup(name);
  842.         cp += len;
  843.  
  844.         rrp->rdata.soa.serial = get32(cp);
  845.         cp += 4;
  846.         rrp->rdata.soa.refresh = get32(cp);
  847.         cp += 4;
  848.         rrp->rdata.soa.retry = get32(cp);
  849.         cp += 4;
  850.         rrp->rdata.soa.expire = get32(cp);
  851.         cp += 4;
  852.         rrp->rdata.soa.minimum = get32(cp);
  853.         cp += 4;
  854.         break;
  855.     case TYPE_TXT:
  856.         /* Just stash */
  857.         rrp->rdata.data = malloc(rrp->rdlength);
  858.         memcpy(rrp->rdata.data,cp,rrp->rdlength);
  859.         cp += rrp->rdlength;
  860.         break;
  861.     default:
  862.         /* Ignore */
  863.         cp += rrp->rdlength;
  864.         break;
  865.     }
  866.     free(name);
  867.     return cp;
  868. }
  869. /* Print a resource record */
  870. static void
  871. putrr(fp,rrp)
  872. FILE *fp;
  873. struct rr *rrp;
  874. {
  875.     if(fp == NULLFILE || rrp == NULLRR)
  876.         return;
  877.  
  878.     fprintf(fp,"%s\t%lu",rrp->name,rrp->ttl);
  879.     if(rrp->class == CLASS_IN)
  880.         fprintf(fp,"\tIN");
  881.     else
  882.         fprintf(fp,"\t%u",rrp->class);
  883.     if(rrp->type < Ndtypes)
  884.         fprintf(fp,"\t%s",Dtypes[rrp->type]);
  885.     else
  886.         fprintf(fp,"\t%u",rrp->type);
  887.     if(rrp->rdlength == 0){
  888.         /* Null data portion, indicates nonexistent record */
  889.         fprintf(fp,"\n");
  890.         return;
  891.     }
  892.     switch(rrp->type){
  893.     case TYPE_CNAME:
  894.     case TYPE_MB:
  895.     case TYPE_MG:
  896.     case TYPE_MR:
  897.     case TYPE_NS:
  898.     case TYPE_PTR:
  899.     case TYPE_TXT:
  900.         /* These are all printable text strings */
  901.         fprintf(fp,"\t%s\n",rrp->rdata.data);
  902.         break;
  903.     case TYPE_A:
  904.         fprintf(fp,"\t%s\n",inet_ntoa(rrp->rdata.addr));
  905.         break;
  906.     case TYPE_MX:
  907.         fprintf(fp,"\t%u\t%s\n",rrp->rdata.mx.pref,
  908.          rrp->rdata.mx.exch);
  909.         break;
  910.     case TYPE_SOA:
  911.         fprintf(fp,"\t%s\t%s\t%lu\t%lu\t%lu\t%lu\t%lu\n",
  912.          rrp->rdata.soa.mname,rrp->rdata.soa.rname,
  913.          rrp->rdata.soa.serial,rrp->rdata.soa.refresh,
  914.          rrp->rdata.soa.retry,rrp->rdata.soa.expire,
  915.          rrp->rdata.soa.minimum);
  916.         break;
  917.     default:
  918.         fprintf(fp,"\n");
  919.         break;
  920.     }
  921. }
  922. /* Add a record to the database only if it doesn't already exist */
  923. void
  924. addit(fp,rrp1)
  925. FILE *fp;
  926. struct rr *rrp1;
  927. {
  928.     register struct rr *rrp;
  929.  
  930.     rewind(fp);
  931.     while((rrp = dfind(fp,rrp1->name,rrp1->type)) != NULLRR){
  932.         if(rrcmp(rrp,rrp1) == 0){
  933.             free_rr(rrp);
  934.             return;
  935.         }
  936.         free_rr(rrp);
  937.     }
  938.     fseek(fp,0L,2);
  939.     putrr(fp,rrp1);
  940. }
  941. static struct dserver *
  942. dslookup(server)
  943. int32 server;
  944. {
  945.     struct dserver *dp;
  946.  
  947.     for(dp = Dlist;dp != NULLDOM;dp = dp->next)
  948.         if(dp->address == server)
  949.             break;
  950.     return dp;
  951. }
  952. /* Free a domain message */
  953. static void
  954. free_dhdr(dp)
  955. struct dhdr *dp;
  956. {
  957.     int i;
  958.  
  959.     if(dp->qdcount != 0){
  960.         for(i=0;i<dp->qdcount;i++)
  961.             free_qu(dp->qlist[i]);
  962.         free((char *)dp->qlist);
  963.     }
  964.     if(dp->ancount != 0){
  965.         for(i=0;i<dp->ancount;i++)
  966.             free_rr(dp->ans[i]);
  967.         free((char *)dp->ans);
  968.     }
  969.     if(dp->nscount != 0){
  970.         for(i=0;i<dp->nscount;i++)
  971.             free_rr(dp->ns[i]);
  972.         free((char *)dp->ns);
  973.     }
  974.     if(dp->arcount != 0){
  975.         for(i=0;i<dp->arcount;i++)
  976.             free_rr(dp->add[i]);
  977.         free((char *)dp->add);
  978.     }
  979. }
  980.  
  981. /* Free a question record */
  982. static void
  983. free_qu(qp)
  984. struct quest *qp;
  985. {
  986.     free(qp->qname);
  987.     free((char *)qp);
  988. }
  989.  
  990. /* Free a resource record */
  991. static void
  992. free_rr(rrp)
  993. struct rr *rrp;
  994. {
  995.     if(rrp == NULLRR)
  996.         return;
  997.     free(rrp->name);
  998.     if(rrp->rdlength != 0){
  999.         switch(rrp->type){
  1000.         case TYPE_CNAME:
  1001.         case TYPE_MB:
  1002.         case TYPE_MG:
  1003.         case TYPE_MR:
  1004.         case TYPE_NS:
  1005.         case TYPE_PTR:
  1006.             free(rrp->rdata.name);
  1007.             break;
  1008.         case TYPE_A:
  1009.             break;    /* Nothing allocated in rdata section */
  1010.         case TYPE_HINFO:
  1011.             free(rrp->rdata.hinfo.cpu);
  1012.             free(rrp->rdata.hinfo.os);
  1013.             break;
  1014.         case TYPE_MX:
  1015.             free(rrp->rdata.mx.exch);
  1016.             break;
  1017.         case TYPE_SOA:
  1018.             free(rrp->rdata.soa.mname);
  1019.             free(rrp->rdata.soa.rname);
  1020.             break;
  1021.         case TYPE_TXT:
  1022.             free(rrp->rdata.data);
  1023.             break;
  1024.         }
  1025.     }
  1026.     free((char *)rrp);
  1027. }
  1028. /* Compare two resource records, returning 0 if equal, nonzero otherwise */
  1029. static int
  1030. rrcmp(rr1,rr2)
  1031. register struct rr *rr1,*rr2;
  1032. {
  1033.     int i;
  1034.  
  1035.     if(rr1 == NULLRR || rr2 == NULLRR)
  1036.         return -1;
  1037.     if((i = strlen(rr1->name)) != strlen(rr2->name))
  1038.         return 1;
  1039.     if((i = strnicmp(rr1->name,rr2->name,i)) != 0)
  1040.         return i;
  1041.     if(rr1->type != rr2->type)
  1042.         return 2;
  1043.     if(rr1->class != rr2->class)
  1044.         return 3;
  1045.     /* Note: rdlengths are not compared because they vary depending
  1046.      * on the representation (ASCII or encoded) this record was
  1047.      * generated from.
  1048.      */
  1049.     switch(rr1->type){
  1050.     case TYPE_A:
  1051.         i = rr1->rdata.addr != rr2->rdata.addr;
  1052.         break;
  1053.     case TYPE_SOA:
  1054.         i = rr1->rdata.soa.serial != rr2->rdata.soa.serial;
  1055.         break;
  1056.     case TYPE_HINFO:
  1057.         i = strcmp(rr1->rdata.hinfo.cpu,rr2->rdata.hinfo.cpu) ||
  1058.             strcmp(rr1->rdata.hinfo.os,rr2->rdata.hinfo.os);
  1059.         break;
  1060.     case TYPE_MX:
  1061.         i = strcmp(rr1->rdata.mx.exch,rr2->rdata.mx.exch);
  1062.         break;
  1063.     case TYPE_MB:
  1064.     case TYPE_MG:
  1065.     case TYPE_MR:
  1066.     case TYPE_NULL:
  1067.     case TYPE_WKS:
  1068.     case TYPE_PTR:
  1069.     case TYPE_MINFO:
  1070.     case TYPE_TXT:
  1071.     case TYPE_NS:
  1072.         i = strcmp(rr1->rdata.data,rr2->rdata.data);
  1073.         break;
  1074.     case TYPE_MD:
  1075.     case TYPE_MF:
  1076.     case TYPE_CNAME:
  1077.         i = strcmp(rr1->rdata.data,rr2->rdata.data);
  1078.         break;
  1079.     }
  1080.     return i;
  1081. }
  1082.